package com.qumap.map;

import com.google.gwt.event.shared.EventBus;
import com.google.gwt.maps.client.base.HasLatLng;
import com.google.gwt.maps.client.event.Event;
import com.google.gwt.maps.client.event.EventCallback;
import com.google.gwt.maps.client.overlay.HasMarker;
import com.qumap.common.event.GlobalEvent;
import com.qumap.common.event.GlobalEventCollection;
import com.qumap.common.event.GlobalEventHandler;
import com.qumap.item.ItemOnMap;
import com.qumap.item.event.ItemEvent;
import com.qumap.item.event.ItemEventCollection;
import com.qumap.item.event.ItemEventHandler;

import javax.inject.Inject;
import java.util.*;

/**
 * Created by IntelliJ IDEA.
 * User: Admin
 * Date: 25.06.11
 * Time: 16:27
 * To change this template use File | Settings | File Templates.
 */
public class MapItemHolder {

    @Inject
    protected IMapView map_view;

    protected EventBus global_event_bus;

    private HashMap<String, TypedItemHolder> all_itmes_holder = new HashMap<String, TypedItemHolder>();

    private Queue<HasMarker> marker_pool = new LinkedList<HasMarker>();

    private boolean need_clear_on_load = true;

    public void init() {
        initListeners();
    }

    protected void initListeners() {

        global_event_bus.addHandler(ItemEventCollection.EventType.Delete.getType(), new ItemEventHandler() {
            @Override
            public void onItemEvent(ItemEvent event) {
               deleteItem(event.getFirstItem());
            }
        });

        global_event_bus.addHandler(ItemEventCollection.EventType.Load.getType(), new ItemEventHandler() {
            @Override
            public void onItemEvent(ItemEvent event) {

                if(needClearOnLoad())
                   clearAllItems();

                for(ItemOnMap event_item: event.getSelectedItems()) {
                    processLoadItem(event_item);
                }
            }
        });

        global_event_bus.addHandler(ItemEventCollection.EventType.ItemTypeRegistered.getType(), new ItemEventHandler() {
            @Override
            public void onItemEvent(ItemEvent event) {
                ItemOnMap registered_item = event.getFirstItem();
                TypedItemHolder new_type_holder = new TypedItemHolder(registered_item.getItemInfo());
                all_itmes_holder.put(new_type_holder.getType(), new_type_holder);
            }
        });

        global_event_bus.addHandler(GlobalEventCollection.EventType.ClearAll.getType(), new GlobalEventHandler() {
            @Override
            public void onGlobalEvent(GlobalEvent event) {
                clearAllItems();
            }
        });

        global_event_bus.addHandler(ItemEventCollection.EventType.ClearTyped.getType(), new ItemEventHandler() {
            @Override
            public void onItemEvent(ItemEvent event) {
                ItemOnMap item_type_to_clear = event.getFirstItem();
                clearTypedItem(item_type_to_clear);
            }
        });

    }

    protected void clearAllItems() {
        for(TypedItemHolder holder_to_clear: all_itmes_holder.values())
            clearTypedHolder(holder_to_clear);

    }

    protected void clearTypedItem(ItemOnMap sample) {
        TypedItemHolder holder = getItemHolder(sample);
        clearTypedHolder(holder);
    }

    protected void clearTypedHolder(TypedItemHolder holder) {
        List<ItemOnMap> all_items = new LinkedList<ItemOnMap>();
        all_items.addAll(holder.getAllItems());
        for(ItemOnMap item_to_remove: all_items)
            deleteItem(item_to_remove);
    }

    protected void processLoadItem(ItemOnMap loaded_item) {
        if(isItemLoad(loaded_item)) {
            updateExistedItem(loaded_item);
        } else {
            storeLoadItem(loaded_item);
            addItem(loaded_item);
        }
    }

    protected boolean isItemLoad(ItemOnMap item) {
        TypedItemHolder item_holder = getItemHolder(item);
        return item_holder.isItemLoad(item);
    }

    protected void updateExistedItem(ItemOnMap loaded_item) {
        TypedItemHolder item_holder = getItemHolder(loaded_item);
        HasMarker marker = item_holder.updateExistedItem(loaded_item);
        updateItemMarker(marker, loaded_item);
    }

    protected void storeLoadItem(ItemOnMap load_item) {
        TypedItemHolder item_holder = getItemHolder(load_item);
        item_holder.storeLoadItem(load_item);
    }

    protected void addItem(ItemOnMap new_item) {
        HasMarker marker = getNewMarker();
        updateItemMarker(marker, new_item);
        marker.setMap(map_view.getMap());
        TypedItemHolder holder = getItemHolder(new_item);
        holder.storeNewItem(new_item, marker);
        marker.setVisible(true);
        onItemAdded(new_item);
    }


    private void updateItemMarker(HasMarker marker, ItemOnMap owner) {
        HasLatLng latlng = map_view.createLatLng(owner.getLattitude(), owner.getLongtitude());
        marker.setPosition(latlng);
        TypedItemHolder holder = getItemHolder(owner);
        holder.setImageToItemMarker(owner, marker);
    }



    protected HasMarker getNewMarker() {
        if(marker_pool.isEmpty())
            return map_view.createMarker();
        return marker_pool.poll();
    }

    private void onItemAdded(ItemOnMap new_item) {
        attachEventToMarker(new_item);
        ItemEvent on_item_added = ItemEventCollection.getCollection().getEvent(ItemEventCollection.EventType.AddedToMap);
        on_item_added.add(new_item);
        global_event_bus.fireEvent(on_item_added);
    }

    protected void attachEventToMarker(final ItemOnMap item) {
        Event.addListener(getItemHolder(item).getItemMarker(item), "click", new EventCallback() {
            @Override
            public void callback() {
                ItemEvent select_event = ItemEventCollection.getCollection().getEvent(ItemEventCollection.EventType.Select);
                select_event.add(item);
                global_event_bus.fireEvent(select_event);
            }
        });
    }

    protected void deleteItem(ItemOnMap item_to_delete) {

        HasMarker item_marker = getItemHolder(item_to_delete).deleteItem(item_to_delete);
        item_marker.setVisible(false);
        detachEventsFromMarker(item_marker);
        marker_pool.add(item_marker);
    }

    public TypedItemHolder getItemHolder(ItemOnMap item) {
        return all_itmes_holder.get(item.getItemInfo().getType());
    }

    public Collection<TypedItemHolder> getAllItemHolders() {
        return all_itmes_holder.values();
    }

    protected void detachEventsFromMarker(HasMarker marker) {
       Event.clearListeners(marker, "click");
    }

    public void setNeedClearOnLoad(boolean value) {
        need_clear_on_load = value;
    }

    public boolean needClearOnLoad() {
        return need_clear_on_load;
    }

    public void setGlobalEventBus(EventBus global_event_bus) {
        this.global_event_bus = global_event_bus;
    }

}
